#include <stdio.h>
#include <string.h>
#include "memory.h"
#include "tree.h"
#include "regalloc.h"
int temp = 0;
ll *current = NULL;
int variables = 0;
int registerID = 0;
reg *eax;
reg *ebx;
reg *ecx;
reg *edx;
reg *esi;
reg *edi;
reg *esp;
reg *ebp;

ll *regalloc(ll *front){
	eax=makeREG_ID(0,"%eax");
	ebx=makeREG_ID(1,"%ebx");
	ecx=makeREG_ID(2,"%ecx");
	edx=makeREG_ID(3,"%edx");
	esi=makeREG_ID(4,"%esi");
	edi=makeREG_ID(5,"%edi");
	esp=makeREG_ID(6,"%esp");
	ebp=makeREG_ID(7,"%ebp");
	current = front;
	if(current!=NULL){
		regallocASC();
	}
	while(current->next != NULL){
		current = current->next;
		regallocASC();
	}
	return front;
}
void regallocREG(reg *reg){
	if(reg->id<8){
		switch(reg->id){
		case 0:
			reg->regid = malloc(strlen("%eax"));
			strcpy(reg->regid, "%eax");
			break;
		case 1:
			reg->regid = malloc(strlen("%ebx"));
			strcpy(reg->regid, "%ebx");
			break;
		case 2:
			reg->regid = malloc(strlen("%ecx"));
			strcpy(reg->regid, "%ecx");
			break;
		case 3:
			reg->regid = malloc(strlen("%edx"));
			strcpy(reg->regid, "%edx");
			break;
		case 4:
			reg->regid = malloc(strlen("%esi"));
			strcpy(reg->regid, "%esi");
			break;
		case 5:
			reg->regid = malloc(strlen("%edi"));
			strcpy(reg->regid, "%edi");
			break;
		case 6:
			reg->regid = malloc(strlen("%esp"));
			strcpy(reg->regid, "%esp");
			break;
		case 7:
			reg->regid = malloc(strlen("%ebp"));
			strcpy(reg->regid, "%ebp");
			break;
		case -42:
			break;
		}
	}else{
		if(reg->id>registerID){
			temp++;
			char *spot;
			spot = (char*) malloc(8);
			sprintf(spot,"-%i",((temp+variables)*4)+12);
			strcat(spot,"(%ebp)");
			reg->regid = spot;
			registerID = reg->id;
		}
	}
}

void regallocASC(){
	asc *asc;
	reg *reg1;
	reg *reg2;
	ll *llLABEL;
	asc = current->asc;
	if(asc!=NULL){
		switch(asc->kind){
		case LABEL:
			break;
		case FUNCLABEL:
			break;
		case MOV:
			regallocREG(asc->par.arguments.first);
			regallocREG(asc->par.arguments.second);
			if((asc->par.arguments.first->id>7||asc->par.arguments.first->id<0) && (asc->par.arguments.second->id>7||asc->par.arguments.second->id<0)){
				reg1 = asc->par.arguments.first;
				llLABEL = makeLL();
				llLABEL->asc->kind= MOV;
				llLABEL->asc->par.arguments.first=reg1;
				llLABEL->asc->par.arguments.second=ebx;
				current->asc->par.arguments.first=ebx;
				insert__before_LL(llLABEL);
			}
			break;
		case MOV_CONST:
			regallocREG(asc->par.arguments_const.second);
			break;
		case PUSH:
			regallocREG(asc->par.arguments.first);
			break;
		case PUSH_CONST:
			break;
		case POP:
			regallocREG(asc->par.arguments.first);
			break;
		case ADD:
			regallocREG(asc->par.arguments.first);
			regallocREG(asc->par.arguments.second);
			if((asc->par.arguments.first->id>7||asc->par.arguments.first->id<0) && (asc->par.arguments.second->id>7||asc->par.arguments.second->id<0)){
				reg1= asc->par.arguments.first;
				llLABEL= makeLL();
				llLABEL->asc->kind= MOV;
				llLABEL->asc->par.arguments.first=reg1;
				llLABEL->asc->par.arguments.second= ebx;
				current->asc->par.arguments.first= ebx;
				insert__before_LL(llLABEL);
			}
			break;
		case ADD_CONST:
			regallocREG(asc->par.arguments_const.second);
			break;
		case SUB:
			regallocREG(asc->par.arguments.first);
			regallocREG(asc->par.arguments.second);
			if((asc->par.arguments.first->id>7||asc->par.arguments.first->id<0) && (asc->par.arguments.second->id>7||asc->par.arguments.second->id<0)){
				reg1= asc->par.arguments.first;
				llLABEL= makeLL();
				llLABEL->asc->kind= MOV;
				llLABEL->asc->par.arguments.first=reg1;
				llLABEL->asc->par.arguments.second= ebx;
				current->asc->par.arguments.first= ebx;
				insert__before_LL(llLABEL);
			}
			break;
		case SUB_CONST:
			regallocREG(asc->par.arguments_const.second);
			break;
		case DIV:
			regallocREG(asc->par.arguments.first);
			reg1 = asc->par.arguments.first;
			llLABEL= makeLL();
			llLABEL->asc->kind= MOV;
			llLABEL->asc->par.arguments.first=reg1;
			llLABEL->asc->par.arguments.second= ebx;
			current->asc->par.arguments.first= ebx;
			insert__before_LL(llLABEL);
			break;
		case DIV_CONST:
			regallocREG(asc->par.arguments_const.second);
			break;
		case MUL:
			regallocREG(asc->par.arguments.first);
			regallocREG(asc->par.arguments.second);
			if((asc->par.arguments.first->id>7||asc->par.arguments.first->id<0) && (asc->par.arguments.second->id>7||asc->par.arguments.second->id<0)){
				reg2= asc->par.arguments.second;
				llLABEL= makeLL();
				llLABEL->asc->kind= MOV;
				llLABEL->asc->par.arguments.first=reg2;
				llLABEL->asc->par.arguments.second= eax;
				current->asc->par.arguments.second= eax;
				insert__before_LL(llLABEL);
			}
			break;
		case MUL_CONST:
			regallocREG(asc->par.arguments_const.second);
			break;
		case AND:
			regallocREG(asc->par.arguments.first);
			regallocREG(asc->par.arguments.second);
			if((asc->par.arguments.first->id>7||asc->par.arguments.first->id<0) && (asc->par.arguments.second->id>7||asc->par.arguments.second->id<0)){
				reg1= asc->par.arguments.first;
				llLABEL= makeLL();
				llLABEL->asc->kind= MOV;
				llLABEL->asc->par.arguments.first=reg1;
				llLABEL->asc->par.arguments.second= ebx;
				current->asc->par.arguments.first= ebx;
				insert__before_LL(llLABEL);
			}
			break;
		case OR:
			regallocREG(asc->par.arguments.first);
			regallocREG(asc->par.arguments.second);
			if((asc->par.arguments.first->id>7||asc->par.arguments.first->id<0) && (asc->par.arguments.second->id>7||asc->par.arguments.second->id<0)){
				reg1= asc->par.arguments.first;
				llLABEL= makeLL();
				llLABEL->asc->kind= MOV;
				llLABEL->asc->par.arguments.first=reg1;
				llLABEL->asc->par.arguments.second= ebx;
				current->asc->par.arguments.first= ebx;
				insert__before_LL(llLABEL);
			}
			break;
		case NEG:
			regallocREG(asc->par.arguments.first);
			break;
		case CMP:
			regallocREG(asc->par.arguments.first);
			regallocREG(asc->par.arguments.second);
			reg1= asc->par.arguments.second;
			llLABEL= makeLL();
			llLABEL->asc->kind= MOV;
			llLABEL->asc->par.arguments.first=reg1;
			llLABEL->asc->par.arguments.second= ebx;
			asc->par.arguments.second= ebx;
			insert__before_LL(llLABEL);
			break;
		case CMP_CONST:
			regallocREG(asc->par.arguments_const.second);
			break;
		case JMP:
			break;
		case JG:
			break;
		case JL:
			break;
		case JLE:
			break;
		case JGE:
			break;
		case JA:
			break;
		case JAE:
			break;
		case JNE:
			break;
		case JE:
			break;
		case CALL:
			break;
		case ALLOC:
			variables = current->asc->par.arguments_const.first;
			break;
		case DEALLOC:
			current->asc->par.arguments_const.first = temp+variables;
			ll *currentsave;
			currentsave = current;
			while(asc->kind!=ALLOC){
				currentsave = currentsave->previous;
				asc = currentsave->asc;
			}
			currentsave->asc->par.arguments_const.first = temp+variables;
			temp = 0;
			registerID = 0;
			break;
		case RETURN:
			break;
		case STATICLINK:
			break;
		case MOVEPOS:
			regallocREG(asc->par.regs.first);
			regallocREG(asc->par.regs.second);
			if(asc->par.regs.first->id>7){
				reg1 = asc->par.regs.first;
				llLABEL= makeLL();
				llLABEL->asc->kind= MOV;
				llLABEL->asc->par.arguments.first=reg1;
				llLABEL->asc->par.arguments.second= eax;
				insert__before_LL(llLABEL);
			}
			break;
		}
	}else{
		fprintf(stderr,"ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
	}
}

void insert__before_LL(ll *tmp){
	tmp->next = current;
	tmp->previous = current->previous;
	current->previous->next = tmp;
	current->previous = tmp;
}

void insert__after_LL(ll *tmp){
	tmp->next = current->next;
	tmp->previous = current;
	current = tmp;
}

ll *makeLL(){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	return llLABEL;
}
